package org.ribizli.games.amoeba;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;

public class FieldView extends View {

  private int mFieldSize;
  private int mMarkSize;
  private final static String TAG = "Amoeba-FieldView";
  private int mMaxScrollX;
  private int mMaxScrollY;
  private char[][] mMarks;
  private Paint mPaintGrid = new Paint();
  private GestureDetector mGestureDetector;
  private Bitmap mBitmapO;
  private Bitmap mBitmapX;
  private char mPlayerMark = 'x';
  private OnMarkListener mListener;
  
  public interface OnMarkListener {
    public void onMark(int x, int y);
  }

  private class MySimpleOnGestureListener extends SimpleOnGestureListener {

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
      if (!isEnabled()) return true;
      int x = ((int)e.getX() + getScrollX()) / mMarkSize;
      int y = ((int)e.getY() + getScrollY()) / mMarkSize;
      if (mMarks[x][y] == 0) {
        putMark(x, y, mPlayerMark);
        if (mListener != null) {
          mListener.onMark(x, y);
        }
      }
      return true;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
        float distanceY) {
      int x = getScrollX() + (int)distanceX, y = getScrollY() + (int)distanceY;
      
      if (x < 0) {
        x = 0;
      }
      if (x >= mMaxScrollX) {
        x = mMaxScrollX;
      }
      if (y < 0) {
        y = 0;
      }
      if (y >= mMaxScrollY) {
        y = mMaxScrollY;
      }
      FieldView.this.scrollTo(x, y);
      return true;
    }
  }
  

  public FieldView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context, attrs);
  }

  public FieldView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
  }

  private void init(Context context, AttributeSet attrs) {
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FieldView);
    mFieldSize = a.getInt(R.styleable.FieldView_fieldSize, 25);
    mMarkSize = a.getInt(R.styleable.FieldView_markSize, 20);
    
    Paint paintX = new Paint();
    paintX.setColor(a.getColor(R.styleable.FieldView_colorX, context.getResources().getColor(R.color.defaultX)));
    paintX.setStrokeWidth(mMarkSize / 5);
    Paint paintO = new Paint();
    paintO.setColor(a.getColor(R.styleable.FieldView_colorO, context.getResources().getColor(R.color.defaultO)));
    paintO.setStrokeWidth(mMarkSize / 5);
    paintO.setStyle(Paint.Style.STROKE);
    mPaintGrid.setColor(a.getColor(R.styleable.FieldView_colorGrid, context.getResources().getColor(R.color.defaultGrid)));
    a.recycle();
    
    
    mBitmapX = Bitmap.createBitmap(mMarkSize, mMarkSize, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(mBitmapX);
    int pad = mMarkSize / 10;
    int px = mMarkSize - pad;
    c.drawLine(pad, pad, px, px, paintX);
    c.drawLine(pad, px, px, pad, paintX);
    mBitmapO = Bitmap.createBitmap(mMarkSize, mMarkSize, Bitmap.Config.ARGB_8888);
    c.setBitmap(mBitmapO);
    px = mMarkSize / 2;
    c.drawCircle(px, px, px - pad - 1, paintO);
    
    mMarks = new char[mFieldSize][mFieldSize];
    mGestureDetector = new GestureDetector(new MySimpleOnGestureListener());
    mGestureDetector.setIsLongpressEnabled(false);
    scrollTo(mMaxScrollX / 2, mMaxScrollY / 2);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Rect clip = canvas.getClipBounds();
//    Log.d(lTag, "Draw: " + clip.left + "," + clip.top + "," + clip.right + ","
//        + clip.bottom);
    int iMax = clip.right / mMarkSize;
    int iMin = clip.left / mMarkSize;
    for (int i = iMin; i <= iMax; i++) {
      canvas.drawLine(i * mMarkSize, clip.top, i * mMarkSize, clip.bottom, mPaintGrid);
    }
    int jMax = clip.bottom / mMarkSize;
    int jMin = clip.top / mMarkSize;
    for (int j = jMin; j <= jMax; j++) {
      canvas.drawLine(clip.left, j * mMarkSize, clip.right, j * mMarkSize, mPaintGrid);
    }
    for (int i = iMin; i <= iMax; i++) {
      for (int j = jMin; j <= jMax; j++) {
        try {
          switch (mMarks[i][j]) {
          case 'x':
            canvas.drawBitmap(mBitmapX, i * mMarkSize, j * mMarkSize, null);
            break;
          case 'o':
            canvas.drawBitmap(mBitmapO, i * mMarkSize, j * mMarkSize, null);
            break;
          default:
            break;
          }
        } catch (Exception e) {
          Log.e(TAG, "Ex", e);
        }
      }
    }
  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    int fSize = mFieldSize * mMarkSize;
    Log.d(TAG, "Size changed: " + w + "," + h + " (" + oldw + "," + oldh + ")");
    mMaxScrollX = fSize - w - 1;
    mMaxScrollY = fSize - h - 1;
    Log.d(TAG, "Max scroll: " + mMaxScrollX + "," + mMaxScrollY);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (mGestureDetector.onTouchEvent(event)) {
      return true;
    } 
    return true;
  }

  @Override
  public boolean onTrackballEvent(MotionEvent event) {
    return super.onTrackballEvent(event);
  }
  
  public void putMark(int x, int y, char what) {
    mMarks[x][y] = what;
    invalidate(x * mMarkSize, y * mMarkSize, (x+1)*mMarkSize, (y+1)*mMarkSize);
  }
  
  public void clear() {
    mMarks = new char[mFieldSize][mFieldSize];
    invalidate();
  }
  
  public void putOpponentMark(int x, int y) {
    putMark(x, y, getOpponentMark());
  }
  
  public void putPlayerMark(int x, int y) {
    putMark(x, y, mPlayerMark);
  }
  
  public void setPlayerMark(char mark) {
    if (mark != 'x' && mark != 'o') {
      return;
    }
    mPlayerMark  = mark;
  }
  
  public char getPlayerMark() {
    return mPlayerMark;
  }
  
  public char getOpponentMark() {
    return mPlayerMark == 'x' ? 'o' : 'x';
  }
  
  public void setOnMarkListener(OnMarkListener l) {
    mListener = l;
  }

  public void markWinnerRow(int[][] winnerRow) {
  	// TODO: implement
  }
}
